using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace Dungeon_Dive
{
    /// <summary>
    /// Camera.
    /// </summary>
    public class Camera : Microsoft.Xna.Framework.GameComponent
    {
        //Camera matrices
        public Matrix View { get; protected set; }
        public Matrix Projection { get; protected set; }

        Vector3 position;
        public Vector3 Position { get { return position; } set { position = value; } }
        public Vector3 Target { get; set; }
        Vector3 up;
        Vector3 direction;
        public bool Free { get; set; }
        float yaw, pitch, roll;

        public Camera(Game game, Vector3 pos, Vector3 target, Vector3 up)
            : base(game)
        {
            position = pos;
            this.Target = target;
            this.up = up;
            direction = this.Target - position;
            direction.Normalize();

            View = Matrix.CreateLookAt(pos, target, up);

            Projection = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.PiOver4,
                (float)Game.Window.ClientBounds.Width /
                (float)Game.Window.ClientBounds.Height,
                1, 10000);
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            KeyboardState keyboardState = Keyboard.GetState();
            //Matrix mx;
            int mouseXDiff = Mouse.GetState().X - Game.Window.ClientBounds.Width / 2;
            int mouseYDiff = Mouse.GetState().Y - Game.Window.ClientBounds.Height / 2;

            if (mouseXDiff != 0)
            {
                //direction += Vector3.Cross(direction, up) * (mouseXDiff * 0.01f);
                yaw -= (mouseXDiff * 0.01f);
            }

            if (mouseYDiff != 0)
            {
                //direction -= up * (mouseYDiff * 0.01f);
                pitch -= (mouseYDiff * 0.01f);
            }

            if (keyboardState.IsKeyDown(Keys.Subtract))
                position.Y += 15f;
            if (keyboardState.IsKeyDown(Keys.Add))
                position.Y -= 15f;
            if (keyboardState.IsKeyDown(Keys.Up))
            {
                position += direction * 10f;
            }
            if (keyboardState.IsKeyDown(Keys.Down))
            {
                position += direction * -10f;
            }
            if (keyboardState.IsKeyDown(Keys.Left))
                position -= Vector3.Cross(direction, up) * 10f;
            if (keyboardState.IsKeyDown(Keys.Right))
                position += Vector3.Cross(direction, up) * 10f;

            if (!Free) View = Matrix.CreateLookAt(position, Target, up);
            else
            {
                direction = Matrix.CreateFromYawPitchRoll(yaw, pitch, roll).Forward;
                View = Matrix.CreateLookAt(position, position + direction, up);
            }

            base.Update(gameTime);
        }
    }
}